//=============================================================================
// ProMesh.NET - .NET Web Application Framework 
//
// Copyright (c) 2003-2008 Philippe Leybaert
//
// Permission is hereby granted, free of charge, to any person obtaining a copy 
// of this software and associated documentation files (the "Software"), to deal 
// in the Software without restriction, including without limitation the rights 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in 
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//=============================================================================

using System;
using System.Reflection;

namespace Activa.ProMesh
{
    public abstract class Controller : IDisposable
    {
        protected static ProMeshHttpResponse   Response { get { return WebAppContext.Response; } }
        protected static IHttpRequest          Request  { get { return WebAppContext.Request;  } }
        protected static IHttpServerUtility    Server   { get { return WebAppContext.Server;   } }
        protected static SessionBase           Session  { get { return WebAppContext.Session;  } }
        protected static ClientDataCollection  GetData  { get { return WebAppContext.GetData;  } }
        protected static ClientDataCollection  PostData { get { return WebAppContext.PostData; } }

        private ControllerClass _controllerClass;
        private TemplateParserContext _templateParserContext;

        private View _view = new View();

        public ViewDataContainer ViewData
        {
            get { return _view.ViewData; }
        }

        public ControlCollection Controls
        {
            get { return _view.Controls; }
        }

        internal void Initialize(ControllerClass controllerClass, TemplateParserContext _parserContext) // parse context used for view components
        {
            _controllerClass = controllerClass;
            _templateParserContext = _parserContext;

            LayoutAttribute layoutAttribute = null;
            ViewAttribute viewAttribute = null;

            if (GetType().IsDefined(typeof(LayoutAttribute),true))
                layoutAttribute = (LayoutAttribute) GetType().GetCustomAttributes(typeof (LayoutAttribute), true)[0];

            if (GetType().IsDefined(typeof(ViewAttribute), true))
                viewAttribute = (ViewAttribute) GetType().GetCustomAttributes(typeof(ViewAttribute), true)[0];

            if (layoutAttribute != null)
                _view.LayoutName = layoutAttribute.LayoutName;

            if (viewAttribute != null)
                _view.ViewName = viewAttribute.ViewName;

            if (_view.ViewName == null)
                _view.ViewName = _controllerClass.Name;

            MapClientData();
        }

        public View View
        {
            get { return _view; }
            internal set { _view = value; }
        }

        public string RequestMethod
        {
            get { return Request.ServerVariables["REQUEST_METHOD"].ToUpper(); }
        }

        public bool IsPost()
        {
            return RequestMethod == "POST";
        }

        public bool IsPost(string buttonName)
        {
            return IsPost() && (!string.IsNullOrEmpty(WebAppContext.PostData[buttonName]));
        }

        private void MapClientData()
        {
            //TODO: Optimize (preload in ControllerClass)
            Type type = GetType();

            MemberInfo[] members = type.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);

            foreach (MemberInfo member in members)
            {
                if (member is MethodInfo)
                    continue;

                if (member.IsDefined(typeof(ClientDataAttribute), true))
                {
                    ClientDataAttribute attribute = (ClientDataAttribute) member.GetCustomAttributes(typeof(ClientDataAttribute), true)[0];


                    if (member is FieldInfo)
                    {
                        object value = WebAppHelper.GetClientValue(attribute, ((FieldInfo)member).FieldType);

                        ((FieldInfo) member).SetValue(this, value);
                    }
                    else if (member is PropertyInfo)
                    {
                        object value = WebAppHelper.GetClientValue(attribute, ((PropertyInfo)member).PropertyType);

                        ((PropertyInfo)member).SetValue(this, value, null);
                    }
                }
            }
        }

        public string Url
        {
            get { return Request.Path; }
        }

        public string UrlWithParameters
        {
            get { return Request.RawUrl; }
        }

        public void RenderView(string viewName)
        {
            _view.ViewName = viewName;
        }

        public void RenderView(string viewName, string layoutName)
        {
            _view.LayoutName = layoutName;
            _view.ViewName = viewName;
        }

        public void ChangeLayout(string layoutName)
        {
            _view.LayoutName = layoutName;
        }

        public void Redirect(string newUrl)
        {
            Response.Redirect(newUrl);
        }

        public void RedirectWithoutParameters()
        {
            Response.Redirect(WebAppContext.Request.Path);
        }

        public void RedirectWithParameters()
        {
            Response.Redirect(WebAppContext.Request.RawUrl);
        }


        private static Controller CreateController(ControllerClass controllerClass, View view)
        {
            Controller controller = controllerClass.CreateController();

            controller._view = view;

            controllerClass.ExecutePreMethods(controller, null);

            controllerClass.RegisterAjaxMethods(controller);

            return controller;
        }

        public static Controller CreateController(string controllerName, View view)
        {
            ControllerClass controllerClass = WebAppConfig.GetControllerClass(controllerName);

            return CreateController(controllerClass, view);
        }

        public static Controller CreateController(Type controllerType, View view)
        {
            ControllerClass controllerClass = WebAppConfig.GetControllerClass(controllerType);

            return CreateController(controllerClass, view);
        }

        public static T CreateController<T>(View view) where T:Controller
        {
            return (T) CreateController(typeof (T), view);
        }

        public void Dispose()
        {
            if (_controllerClass != null)
            {
                _controllerClass.ExecutePostMethods(this, _templateParserContext);

                _controllerClass.RegisterAjaxMethods(this);
            }
        }
    }
}